package com.zzyl.nursing.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.util.TypeUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.huaweicloud.sdk.iotda.v5.IoTDAClient;
import com.huaweicloud.sdk.iotda.v5.model.DeviceShadowData;
import com.huaweicloud.sdk.iotda.v5.model.DeviceShadowProperties;
import com.huaweicloud.sdk.iotda.v5.model.ShowDeviceShadowRequest;
import com.huaweicloud.sdk.iotda.v5.model.ShowDeviceShadowResponse;
import com.zzyl.common.exception.base.BaseException;
import com.zzyl.common.utils.StringUtils;
import com.zzyl.framework.web.service.TokenService;
import com.zzyl.nursing.domain.*;
import com.zzyl.nursing.dto.FamilyDto;
import com.zzyl.nursing.dto.LoginUserDto;
import com.zzyl.nursing.mapper.FamilyMemberMapper;
import com.zzyl.nursing.service.*;
import com.zzyl.nursing.vo.*;
import io.jsonwebtoken.Claims;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 老人家属Service业务层处理
 * 
 * @author mr.wu
 * @date 2025-05-23
 */
@Service
public class FamilyMemberServiceImpl extends ServiceImpl<FamilyMemberMapper, FamilyMember> implements IFamilyMemberService
{
    @Autowired
    private FamilyMemberMapper familyMemberMapper;

    /**
     * 查询老人家属
     * 
     * @param id 老人家属主键
     * @return 老人家属
     */
    @Override
    public FamilyMember selectFamilyMemberById(Long id)
    {
        return getById(id);
    }

    /**
     * 查询老人家属列表
     * 
     * @param familyMember 老人家属
     * @return 老人家属
     */
    @Override
    public List<FamilyMember> selectFamilyMemberList(FamilyMember familyMember)
    {
        return familyMemberMapper.selectFamilyMemberList(familyMember);
    }

    /**
     * 新增老人家属
     * 
     * @param familyMember 老人家属
     * @return 结果
     */
    @Override
    public int insertFamilyMember(FamilyMember familyMember)
    {
        return save(familyMember) ? 1 : 0;
    }

    /**
     * 修改老人家属
     * 
     * @param familyMember 老人家属
     * @return 结果
     */
    @Override
    public int updateFamilyMember(FamilyMember familyMember)
    {
        return updateById(familyMember) ? 1 : 0;
    }

    /**
     * 批量删除老人家属
     * 
     * @param ids 需要删除的老人家属主键
     * @return 结果
     */
    @Override
    public int deleteFamilyMemberByIds(Long[] ids)
    {
        return removeByIds(Arrays.asList(ids)) ? 1 : 0;
    }

    /**
     * 删除老人家属信息
     * 
     * @param id 老人家属主键
     * @return 结果
     */
    @Override
    public int deleteFamilyMemberById(Long id)
    {
        return removeById(id) ? 1 : 0;
    }

    @Autowired
    private WechatService wechatService;

    /**
     * 用户昵称名前缀集合
     */
    private static List<String> NICK_NAME_PREFIX_LIST = Arrays.asList("钱途无量",
            "大桔大利",
            "日富一日",
            "好柿开花",
            "柿柿如意",
            "一椰暴富",
            "大柚所为",
            "杨梅吐气",
            "天生荔枝");

    @Autowired
    private TokenService tokenService;

    /**
     * 小程序登录
     *
     * @param dto
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public LoginUserVo login(LoginUserDto dto) {
        //1. 调用微信小程序登录接口获取openId
        String openId = wechatService.getOpenId(dto.getCode());
        if(StringUtils.isBlank(openId)) {
            throw new BaseException("获取openId失败");
        }

        //2. 根据openId查询用户数据
        FamilyMember member = this.lambdaQuery().eq(FamilyMember::getOpenId, openId).one();

        //3. 如果用户不存在，则新增用户（自动注册）
        if(member==null) {
            Collections.shuffle(NICK_NAME_PREFIX_LIST);

            //随机生成昵称
            String nickName = NICK_NAME_PREFIX_LIST.get(0) + RandomStringUtils.randomNumeric(4);

            member = FamilyMember.builder().name(nickName).openId(openId).build();
            boolean result = this.save(member);
            if(!result) {
                throw new BaseException("新增用户失败");
            }
        }

        //4. 判断用户手机号如果不存在，则调用微信获取手机号接口得到手机号
        if(StringUtils.isBlank(member.getPhone())) {
            String phone = wechatService.getPhone(dto.getPhoneCode());
            if(StringUtils.isBlank(phone)){
                throw new BaseException("获取手机号失败");
            }

            //5. 得到手机号后则完成用户表的更新
            boolean result = this.lambdaUpdate().eq(FamilyMember::getId, member.getId())
                    .set(FamilyMember::getPhone, phone).update();
            if(!result) {
                throw new BaseException("更新手机号失败");
            }
        }

        //6. 生成登录成功用户的令牌（Token）
        Map<String,Object> userMap = new HashMap<>();
        userMap.put("userId", member.getId());//设置用户
        userMap.put("name",member.getName());//用户昵称
        String token = tokenService.createToken(userMap);//生成令牌

        //7. 构建响应数据
        return LoginUserVo.builder().nickName(member.getName()).token(token).build();
    }

    @Autowired
    private IElderService elderService;
    @Autowired
    private IFamilyMemberElderService familyMemberElderService;


    /**
     * 绑定家人
     * @param dto
     */
    @Override
    public void add(FamilyDto dto, HttpServletRequest request) {

        Elder elder =this.elderService.lambdaQuery()
                .eq(Elder::getIdCardNo, dto.getIdCard())//获取老人的身份证号
                .eq(Elder::getName,dto.getName())//获取老人的姓名
                .one();
        if (elder==null){
            throw new BaseException("老人数据不等于空");
        }
        FamilyMemberElder familyMemberElder = new FamilyMemberElder();

        String token = tokenService.getToken(request);
        Claims claims = tokenService.parseToken(token);
        Long userId = Long.valueOf(claims.get("userId").toString());
        familyMemberElder.setRemark(dto.getRemark());//设置备注信息
        familyMemberElder.setFamilyMemberId(userId);
        familyMemberElder.setElderId(elder.getId());
        familyMemberElder.setElderName(elder.getName());
        this.familyMemberElderService.save(familyMemberElder);
    }

    /**
     * 查询家人列表
     *
     * @return
     */
    @Override
    public List<FamilyMemberVO> usermy(HttpServletRequest request) {
        String token = tokenService.getToken(request);
        Claims claims = tokenService.parseToken(token);
        Long userId = Long.valueOf(claims.get("userId").toString());


        List <FamilyMemberElder> familyMemberElderList = familyMemberElderService.lambdaQuery()
                .eq(FamilyMemberElder::getFamilyMemberId, userId)
                .list();
        List<FamilyMemberVO> collect = familyMemberElderList.stream().map(x -> {
            Elder elder = elderService.getById(x.getElderId());
            FamilyMemberVO vo = new FamilyMemberVO();
            BeanUtils.copyProperties(x, vo);
//            vo.setId(x.getId());
//            vo.setFamilyMemberId(x.getFamilyMemberId());
            if (elder!=null){
                vo.setElderName(elder.getName());
            }
            vo.setElderId(x.getElderId());
            return vo;
        }).collect(Collectors.toList());
        return collect;
    }

    @Autowired
    private IBedService bedService;
    @Autowired
    private IRoomService roomService;

    @Autowired
    private IDeviceService  deviceService;

    @Override
    public List<FamilyMemberMyVo> pageList(HttpServletRequest request) {
        //1.获取id
        String token = tokenService.getToken(request);
        Claims claims = tokenService.parseToken(token);
        Long userId = Long.valueOf(claims.get("userId").toString());
        List<FamilyMemberElder> familyMemberElderList = familyMemberElderService
                .lambdaQuery()
                .eq(FamilyMemberElder::getFamilyMemberId, userId).list();

        List<FamilyMemberMyVo> memberMyVoList = familyMemberElderList.stream().map(x -> {
            FamilyMemberMyVo vo = new FamilyMemberMyVo();
            vo.setMid(userId);
            vo.setMremark(x.getRemark());
            Elder elder = elderService.lambdaQuery().eq(Elder::getId, x.getElderId()).one();//获取老人id
            vo.setElderId(elder.getId());
            vo.setName(elder.getName());
            vo.setImage(elder.getImage());
            Bed bed = bedService.lambdaQuery().eq(Bed::getId, elder.getBedId()).one();
            Room room = roomService.lambdaQuery().eq(Room::getId, bed.getRoomId()).one();
            vo.setBedNumber(elder.getBedNumber());
            vo.setTypeName(room.getTypeName());
            Device device = deviceService.lambdaQuery().eq(Device::getBindingLocation,elder.getId()).one();
            vo.setIotId(device.getIotId());
            vo.setDeviceName(device.getDeviceName());
            vo.setProductKey(device.getProductKey());
            return vo;
        }).collect(Collectors.toList());
        return memberMyVoList;
    }

    @Autowired
    private IoTDAClient client;
    /**
     * 查询健康数据
     *
     * @param deviceInfo
     * @return
     */
    @Override
    public Map<String, Object> queryDevicePropertyStatus(DeviceInfo deviceInfo) {
        //1.从数据库中获取数据,判断该产品设备是否存在
        Device device = deviceService.lambdaQuery().eq(Device::getDeviceName, deviceInfo.getDeviceName())
                .eq(Device::getProductKey, deviceInfo.getProductKey())
                .one();
        if (device==null){
            throw new BaseException("设备名与产品key对应设备不存在");
        }
        //2.从华为云中获取数据,设备影子数据
        String deviceId = device.getIotId();
        ShowDeviceShadowRequest request = new ShowDeviceShadowRequest();
        request.withDeviceId(deviceId);
        ShowDeviceShadowResponse response = client.showDeviceShadow(request);
        if (response==null){
            throw new BaseException("从华为云中获取数据失败");
        }
        //3.封装数据
        List<DeviceShadowData> shadowDataList = response.getShadow();
        if (CollUtil.isEmpty(shadowDataList)){
            throw new BaseException("从华为云中获取影子数据为空");
        }
        //获取返回的设备影子数据列表中的第一个设备数据
        DeviceShadowData shadowData = shadowDataList.get(0);
        //获取实际的上报数据
        DeviceShadowProperties reported = shadowData.getReported();
        //获取上报时间
        String eventTimeStr = reported.getEventTime();
        //转为东八区的格式
        LocalDateTime eventTime = OffsetDateTime.parse(eventTimeStr, DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmssX"))
                .atZoneSameInstant(ZoneId.of("Asia/Shanghai"))
                .toLocalDateTime();
        long epochMilli = eventTime.atZone(ZoneId.of("Asia/Shanghai")).toInstant().toEpochMilli();
        //获取属性
        JSONObject properies = JSONUtil.parseObj(reported.getProperties());
        List<Map<String,Object>> mapList = new ArrayList<>();

        properies.forEach((k,v)->{
            //封装属性
            Map<String,Object> property = new HashMap<>();
            property.put("dataType", TypeUtils.getTypeName(v.getClass()));
            property.put("identifier",k);
            property.put("name",v);
            property.put("time",epochMilli);
            property.put("value",Math.round((Double) v));
            property.put("unit","");
            mapList.add(property);
        });

        //4.返回数据
        Map<String,Object> resultMap = new HashMap<>();
        Map<String,Object> propertyStatusInfo = new HashMap<>();

        Integer j = null;
        Integer k = null;
        //调整mapList中的心率与电量的顺序
        for (int i = 0; i < mapList.size(); i++) {
            Map<String, Object> map = mapList.get(i);
            if (map.values().contains("HeartRate")){
                j = i;
            }else if (map.values().contains("BatteryPercentage")){
                k = i;
            }
            if (j!=null&&k!=null){
                //获取心率与电量对应的索引
                Collections.swap(mapList,j,k);
                break;
            }
        }

        propertyStatusInfo.put("propertyStatusInfo",mapList);
        resultMap.put("list",propertyStatusInfo);
        return resultMap;
    }


    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private IDeviceDataService deviceDataService;
    /**
     * 按天统计查询指标数据
     *
     * @param functionId
     * @param startTime
     * @param endTime
     * @param iotId
     * @return
     */
    @Override
    public List<QueryDayVo> queryDeviceDataListByDay(String functionId, Long startTime, Long endTime, String iotId) {
        //1.判断设备是否存在
        Device device = deviceService.lambdaQuery().eq(Device::getIotId, iotId).one();
        if (device==null){
            throw new BaseException("设备不存在");
        }
        //2.从缓存中获取数据
        /*String cacheKey = String.format(CacheConstants.IOT_DEVICE_DATA_LIST_BY_DAY,functionId,startTime,endTime,iotId);
        String resultJSON = redisTemplate.opsForValue().get(cacheKey);
        if (StringUtils.isNotBlank(resultJSON)){
            JSONArray jsonArray = JSONUtil.parseArray(resultJSON);
            List<QueryDayVo> dataList = new ArrayList<>();
            //获取单个的对象
            for (int i = 0; i < jsonArray.size(); i++) {
                JSONObject jsonObject = jsonArray.getJSONObject(i);
                QueryDayVo queryDayVo = new QueryDayVo();
                queryDayVo.setDateTime(jsonObject.getStr("dateTime"));
                queryDayVo.setDataValue(Double.valueOf(jsonObject.getStr("dataValue")));
                dataList.add(queryDayVo);
            }
            return dataList;
        }*/
        //3.缓存中没有数据从数据库中获取
        List<DeviceData> deviceDataList = deviceDataService.lambdaQuery().eq(DeviceData::getIotId, iotId)
                .eq(DeviceData::getFunctionId, functionId)
                .list();
        // 在 Java 中过滤时间范围
        if (CollUtil.isNotEmpty(deviceDataList)) {
            deviceDataList = deviceDataList.stream()
                    .filter(data -> {
                        // 将 LocalDateTime 转为毫秒时间戳
                        long alarmTimeMillis = data.getAlarmTime()
                                .atZone(ZoneId.of("Asia/Shanghai"))
                                .toInstant()
                                .toEpochMilli();

                        return alarmTimeMillis >= startTime && alarmTimeMillis <= endTime;
                    }).collect(Collectors.toList());
        }
        if (CollUtil.isEmpty(deviceDataList)){
            return new ArrayList<>();
        }
        //4.返回数据
        //4.1按照小时聚合返回,每小时平均值
        Map<String, List<Double>> hourlyDataMap = new LinkedHashMap<>();

        for (DeviceData data : deviceDataList) {
            LocalDateTime dateTime = data.getAlarmTime();
            String hourKey = String.format("%02d:%02d", dateTime.getHour(), 0); // 如 "08:00"
            Double value = Double.valueOf(data.getDataValue());

            List<Double> values = hourlyDataMap.get(hourKey);
            if (values == null) {
                values = new ArrayList<>();
                hourlyDataMap.put(hourKey, values);
            }
            values.add(value);
        }

        // 5. 构造返回结果：遍历 map，计算每个小时的平均值，并封装成 VO 对象
        List<QueryDayVo> result = new ArrayList<>();

        for (int hour = 0; hour<24 ;hour++) {
            String time = String.format("%02d:00",hour);
            //如果不为空,就是time,为空设置为空列表
            List<Double> values = hourlyDataMap.getOrDefault(time,Collections.emptyList());

            // 计算平均值
            double average = values.stream()
                    .mapToDouble(Double::doubleValue)
                    .average()
                    .orElse(0.0); // 如果为空，默认返回 0.0

            // 封装 VO 对象
            QueryDayVo vo = new QueryDayVo();
            vo.setDateTime(time);
            vo.setDataValue(Math.round(average*10)/10.0);

            result.add(vo);
        }
        // 6. 返回最终结果
        return result;
    }


    /**
     * 按周统计查询指标数据
     *
     * @param functionId
     * @param startTime
     * @param endTime
     * @param iotId
     * @return
     */
    @Override
    public List<QueryWeekVo> queryDeviceDataListByWeek(String functionId, Long startTime, Long endTime, String iotId) {
        //1.判断设备是否存在
        Device device = deviceService.lambdaQuery().eq(Device::getIotId, iotId).one();
        if (device==null){
            throw new BaseException("设备数据不存在");
        }

        //2.获取设备数据
        List<DeviceData> deviceDataList = deviceDataService.lambdaQuery().eq(DeviceData::getFunctionId, functionId)
                .eq(DeviceData::getIotId, iotId).list();
        if (CollUtil.isEmpty(deviceDataList)){
            throw new BaseException("数据不存在1");
        }
        //再根据时间进行筛选,遍历获取到的数据
        Long finalStartTime = startTime;
        deviceDataList = deviceDataList.stream().filter(data->{
            long epochMilli = data.getAlarmTime()
                    .atZone(ZoneId.of("Asia/Shanghai"))
                    .toInstant()
                    .toEpochMilli();
            return epochMilli>= finalStartTime && epochMilli<=endTime;
        }).collect(Collectors.toList());
        if (CollUtil.isEmpty(deviceDataList)){
            throw new BaseException("数据不存在2");
        }
        //3.参数中给的时间范围是一周,按天进行数据聚合
        Map<String,List<Double>> mapList = new LinkedHashMap<>();
        for (DeviceData deviceData : deviceDataList) {
            LocalDateTime alarmTime = deviceData.getAlarmTime();//格式:2025-06-02 14:31:21
            String strTime = alarmTime.toLocalDate().toString();//格式2025-06-02
            //以第一个"-"为分隔符获取后面的,并把第二个"-"替换为.
            String time = strTime.substring(5).replace("-", ".");//格式"06.02"
            Double value = Double.valueOf(deviceData.getDataValue());

            List<Double> values = mapList.get(time);
            if (CollUtil.isEmpty(values)){
                values = new ArrayList<>();
                mapList.put(time,values);
            }
            values.add(value);
        }

        //4.构造返回结果,遍历,计算每天的平均值,并封装为vo对象
        List<QueryWeekVo> result = new ArrayList<>();

        while (startTime<endTime){
            LocalDateTime dateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(startTime), ZoneId.of("Asia/Shanghai"));//获取最开始时间
            String key = dateTime.toLocalDate().toString().substring(5).replace("-", ".");//获取最开始时间对应的键
            //获取键对应的值
            List<Double> values = mapList.get(key);
            //获取键的平均值,没有设计为0
            double average = CollUtil.isEmpty(values) ? 0:values.stream().mapToDouble(Double::doubleValue).average().orElse(0.0);
            QueryWeekVo queryWeekVo = new QueryWeekVo();
            queryWeekVo.setDateTime(key);
            queryWeekVo.setDataValue((int) average);
            result.add(queryWeekVo);
            startTime+=24*60*60*1000;
        }
        return result;
    }
}
